#include "video_renderer.h"
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/sdp/sdp.h>
#include <gst/webrtc/webrtc.h>
#include <libsoup/soup.h>
#include <json-glib/json-glib.h>
#include <gio/gio.h>
#include <stdio.h>
#include <string.h>

static GstElement *pipeline = NULL;
static GstElement *appsrc = NULL;
static GstElement *webrtcbin = NULL;
static SoupWebsocketConnection *ws_conn = NULL;
static GMainLoop *main_loop = NULL;
static guint64 frame_count = 0;
static gboolean webrtc_loop_started = FALSE;
static void webrtc_renderer_start(video_renderer_t *renderer);

#define WS_URL "ws://192.168.100.25:8443"

static gpointer webrtc_loop_thread(gpointer user_data)
{
    main_loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(main_loop);
    return NULL;
}

static void destroy_webrtc_pipeline()
{
    if (pipeline)
    {
        g_print("🧹 正在销毁旧的 WebRTC pipeline...\n");
        gst_element_set_state(pipeline, GST_STATE_NULL);
        gst_object_unref(pipeline);
        pipeline = NULL;
    }
    appsrc = NULL;
    webrtcbin = NULL;
}

static void send_json(JsonBuilder *builder)
{
    JsonGenerator *gen = json_generator_new();
    JsonNode *root = json_builder_get_root(builder);
    json_generator_set_root(gen, root);
    gchar *text = json_generator_to_data(gen, NULL);
    g_print("📨 发送 JSON: %s\n", text);
    soup_websocket_connection_send_text(ws_conn, text);
    g_free(text);
    g_object_unref(gen);
    json_node_free(root);
}

static void on_ice_candidate(GstElement *webrtcbin, guint mlineindex, gchar *candidate, gpointer user_data)
{
    JsonBuilder *b = json_builder_new();
    json_builder_begin_object(b);
    json_builder_set_member_name(b, "type");
    json_builder_add_string_value(b, "icecandidate");
    json_builder_set_member_name(b, "candidate");
    json_builder_begin_object(b);
    json_builder_set_member_name(b, "candidate");
    json_builder_add_string_value(b, candidate);
    json_builder_set_member_name(b, "sdpMLineIndex");
    json_builder_add_int_value(b, mlineindex);
    json_builder_end_object(b);
    json_builder_end_object(b);
    send_json(b);
    g_object_unref(b);
}

static void on_offer_created(GstPromise *promise, gpointer user_data)
{
    GstWebRTCSessionDescription *offer = NULL;
    const GstStructure *reply = gst_promise_get_reply(promise);
    g_print("🧪 Offer 回调结构体: %s\n", gst_structure_to_string(reply));
    gst_structure_get(reply, "offer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
    gst_promise_unref(promise);

    if (!offer)
    {
        g_printerr("❌ offer 为空，无法设置本地描述\n");
        return;
    }

    g_signal_emit_by_name(webrtcbin, "set-local-description", offer, NULL);

    gchar *sdp_str = gst_sdp_message_as_text(offer->sdp);

    JsonBuilder *b = json_builder_new();
    json_builder_begin_object(b);
    json_builder_set_member_name(b, "type");
    json_builder_add_string_value(b, "offer");

    json_builder_set_member_name(b, "offer");
    json_builder_begin_object(b);
    json_builder_set_member_name(b, "type");
    json_builder_add_string_value(b, "offer");
    json_builder_set_member_name(b, "sdp");
    json_builder_add_string_value(b, sdp_str);
    json_builder_end_object(b);
    json_builder_end_object(b);

    send_json(b);
    g_object_unref(b);
    g_free(sdp_str);
}

static void on_ws_message_cb(SoupWebsocketConnection *conn, SoupWebsocketDataType type, GBytes *msg, gpointer user_data)
{
    gsize size;
    const gchar *data = g_bytes_get_data(msg, &size);
    JsonParser *parser = json_parser_new();
    if (!json_parser_load_from_data(parser, data, size, NULL))
        return;
    JsonObject *obj = json_node_get_object(json_parser_get_root(parser));
    const gchar *type_str = json_object_get_string_member(obj, "type");

    if (g_strcmp0(type_str, "answer") == 0)
    {
        JsonObject *answer = json_object_get_object_member(obj, "answer");
        const gchar *sdp = json_object_get_string_member(answer, "sdp");
        GstSDPMessage *sdp_msg;
        gst_sdp_message_new(&sdp_msg);
        gst_sdp_message_parse_buffer((guint8 *)sdp, strlen(sdp), sdp_msg);
        GstWebRTCSessionDescription *desc = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_ANSWER, sdp_msg);
        g_signal_emit_by_name(webrtcbin, "set-remote-description", desc, NULL);
        gst_webrtc_session_description_free(desc);
        g_print("✅ answer 已设置\n");
    }
    else if (g_strcmp0(type_str, "icecandidate") == 0)
    {
        JsonObject *cand = json_object_get_object_member(obj, "candidate");
        const gchar *candidate = json_object_get_string_member(cand, "candidate");
        int sdp_mline_index = json_object_get_int_member(cand, "sdpMLineIndex");
        g_signal_emit_by_name(webrtcbin, "add-ice-candidate", sdp_mline_index, candidate);
        g_print("✅ ICE candidate 已添加\n");
    }
    else if (g_strcmp0(type_str, "register") == 0)
    {
        const gchar *role = json_object_get_string_member(obj, "role");
        g_print("🧠 收到 register: %s\n", role);
        if (g_strcmp0(role, "browser") == 0)
        {
            g_print("🎯 Browser 已注册，重建 pipeline 并发送 offer...\n");
            destroy_webrtc_pipeline();
            webrtc_renderer_start(NULL);
            GstPromise *promise = gst_promise_new_with_change_func(on_offer_created, NULL, NULL);
            g_signal_emit_by_name(webrtcbin, "create-offer", NULL, promise);
        }
    }
    g_object_unref(parser);
}

static void on_ws_connected_cb(GObject *source, GAsyncResult *res, gpointer user_data)
{
    GError *error = NULL;
    ws_conn = soup_session_websocket_connect_finish(SOUP_SESSION(source), res, &error);
    if (!ws_conn)
    {
        g_printerr("❌ WebSocket 连接失败: %s\n", error->message);
        g_error_free(error);
        return;
    }
    g_signal_connect(ws_conn, "message", G_CALLBACK(on_ws_message_cb), NULL);

    JsonBuilder *b = json_builder_new();
    json_builder_begin_object(b);
    json_builder_set_member_name(b, "type");
    json_builder_add_string_value(b, "register");
    json_builder_set_member_name(b, "role");
    json_builder_add_string_value(b, "streamer");
    json_builder_end_object(b);
    send_json(b);
    g_print("📤 Streamer 注册消息已发送\n");
    g_object_unref(b);
}

static void setup_webrtc_signaling()
{
    SoupSession *session = soup_session_new();
    SoupMessage *msg = soup_message_new(SOUP_METHOD_GET, WS_URL);
    soup_session_websocket_connect_async(session, msg, NULL, NULL, 0, NULL, on_ws_connected_cb, NULL);
}

static void webrtc_renderer_start(video_renderer_t *renderer)
{
    g_print("🚀 正在启动 WebRTC renderer...\n");
    frame_count = 0;
    gst_init(NULL, NULL);

    // pipeline = gst_parse_launch(
    //     "appsrc name=mysrc is-live=true format=time do-timestamp=true ! "
    //     "h264parse ! avdec_h264 ! videoconvert ! video/x-raw,format=I420 ! "
    //     "x264enc tune=zerolatency bitrate=2000 speed-preset=ultrafast ! "
    //     "rtph264pay pt=96 config-interval=1 ! "
    //     "application/x-rtp,media=video,encoding-name=H264,payload=96 ! "
    //     "webrtcbin name=sendrecv",
    //     NULL);

    // pipeline = gst_parse_launch(
    //     "appsrc name=mysrc is-live=true format=time do-timestamp=true ! "
    //     "h264parse ! avdec_h264 ! videoconvert ! x264enc tune=zerolatency speed-preset=ultrafast bitrate=2000 key-int-max=30 ! "
    //     "h264parse config-interval=1 ! rtph264pay pt=96 config-interval=1 ! "
    //     "application/x-rtp,media=video,encoding-name=H264,payload=96 ! webrtcbin name=sendrecv",
    //     NULL);

    pipeline = gst_parse_launch(
        "appsrc name=mysrc is-live=true format=time do-timestamp=true ! "
        "queue max-size-bytes=1048576 leaky=2 ! "  // 1MB，丢尾帧
        "h264parse ! avdec_h264 ! videoconvert ! x264enc tune=zerolatency speed-preset=superfast bitrate=1000 key-int-max=30 ! "
        "h264parse config-interval=1 ! rtph264pay pt=96 config-interval=1 ! "
        "application/x-rtp,media=video,encoding-name=H264,payload=96 ! webrtcbin name=sendrecv",
        NULL);

    appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "mysrc");

    g_object_set(G_OBJECT(appsrc),
        "is-live", TRUE,
        "format", GST_FORMAT_TIME,
        "do-timestamp", TRUE,
        "block", FALSE,
        "max-bytes", 2 * 1024 * 1024,
        "leaky-type", 2,  // 下游拥堵时丢弃旧帧
        NULL);

    GstCaps *caps = gst_caps_from_string(
        "video/x-h264, stream-format=byte-stream, alignment=au");
    g_object_set(G_OBJECT(appsrc), "caps", caps, "format", GST_FORMAT_TIME, NULL);
    gst_caps_unref(caps);

    webrtcbin = gst_bin_get_by_name(GST_BIN(pipeline), "sendrecv");
    g_signal_connect(webrtcbin, "on-ice-candidate", G_CALLBACK(on_ice_candidate), NULL);

    if (!webrtc_loop_started)
    {
        g_thread_new("webrtc-loop", webrtc_loop_thread, NULL);
        webrtc_loop_started = TRUE;
    }
    setup_webrtc_signaling();
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_print("✅ WebRTC pipeline started\n");
}

static void webrtc_renderer_render(video_renderer_t *renderer, raop_ntp_t *ntp, unsigned char *data, int data_len, uint64_t pts, int type)
{
    if (!appsrc || !data || data_len < 4)
        return;

    if ((data[4] & 0x1F) == 7)
        g_print("→ SPS\n");
    else if ((data[4] & 0x1F) == 8)
        g_print("→ PPS\n");
    else if ((data[4] & 0x1F) == 5)
        g_print("→ IDR\n");
    else
        g_print("→ 非关键帧\n");

    GstBuffer *buffer = gst_buffer_new_allocate(NULL, data_len, NULL);
    gst_buffer_fill(buffer, 0, data, data_len);
    GST_BUFFER_PTS(buffer) = gst_util_uint64_scale(frame_count++, GST_SECOND, 30);
    GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(1, GST_SECOND, 30);
    GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_LIVE);

    GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
    if (ret != GST_FLOW_OK)
    {
        g_printerr("❌ push buffer 失败: %d\n", ret);
    }
}

// static void webrtc_renderer_render(video_renderer_t *renderer, raop_ntp_t *ntp, unsigned char *data, int data_len, uint64_t pts, int type) {
//     if (!appsrc || !data || data_len < 4) return;

//     // NALU 类型
//     guint8 nalu_type = data[4] & 0x1F;
//     const char *nalu_name = NULL;
//     gboolean is_keyframe = FALSE;

//     switch (nalu_type) {
//         case 5: nalu_name = "IDR"; is_keyframe = TRUE; break;
//         case 7: nalu_name = "SPS"; is_keyframe = TRUE; break;
//         case 8: nalu_name = "PPS"; is_keyframe = TRUE; break;
//         default: nalu_name = "非关键帧"; break;
//     }

//     g_print("→ %s\n", nalu_name);

//     // // 非关键帧节流（只保留部分非关键帧）
//     // GstAppSrc *src = GST_APP_SRC(appsrc);
//     // GstBufferList *buflist = NULL;
//     // g_object_get(src, "current-level-bytes", &buflist, NULL);

//     // // 超过 1MB 缓冲时，才丢弃部分非关键帧
//     // guint64 level = 0;
//     // g_object_get(src, "current-level-bytes", &level, NULL);
//     // if (!is_keyframe && level > 1024 * 1024) {
//     //     g_print("⚠️ 丢弃非关键帧（缓冲超载: %" G_GUINT64_FORMAT "）\n", level);
//     //     return;
//     // }

//     // 创建 GStreamer buffer
//     GstBuffer *buffer = gst_buffer_new_allocate(NULL, data_len, NULL);
//     gst_buffer_fill(buffer, 0, data, data_len);

//     // 设置时间戳
//     GST_BUFFER_PTS(buffer) = pts * GST_MSECOND;
//     GST_BUFFER_DTS(buffer) = pts * GST_MSECOND;
//     GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, 30); // 假定 30fps

//     // 推送到 appsrc
//     GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
//     if (ret != GST_FLOW_OK) {
//         g_printerr("❌ push buffer 失败: %d\n", ret);
//     }

//     frame_count++;
// }

static void webrtc_renderer_destroy(video_renderer_t *renderer)
{
    if (pipeline)
    {
        gst_element_set_state(pipeline, GST_STATE_NULL);
        gst_object_unref(pipeline);
        pipeline = NULL;
        appsrc = NULL;
        webrtcbin = NULL;
    }
}

static void webrtc_renderer_update_background(video_renderer_t *renderer, int show)
{
    g_printerr("🧱 WebRTC renderer background update: show=%d (忽略)\n", show);
}

video_renderer_t *get_video_renderer_webrtc()
{
    static video_renderer_t r;
    static video_renderer_funcs_t funcs = {
        .start = webrtc_renderer_start,
        .render_buffer = webrtc_renderer_render,
        .flush = NULL,
        .destroy = webrtc_renderer_destroy,
        .update_background = webrtc_renderer_update_background};
    memset(&r, 0, sizeof(r));
    r.funcs = &funcs;
    return &r;
}
